#include <stdlib.h>
#include <stdio.h>
#include "ubt_com/cJSON.h"
#include "ubt_com/ubt_com_util.h"
#include "ubt_com/ubt_proto_nav.h"

namespace ubt_proto_nav
{
int ubtNavEncodeComRsp(std::string&	buf, ubt_nav_msg_com_rsp *pComRsp, std::string& failDesc)
{
    char bufTmp[64];
    sprintf(bufTmp, "result=%d&desc=", pComRsp->result);
    buf += std::string(bufTmp) + pComRsp->desc;
    return 0;
}

int _JsonEncodeLine(cJSON *node, Line *pLine, std::string& failMsg)
{
    cJSON_AddStringToObject(node, "type", pLine->type.c_str());
    cJSON *pointsNode = cJSON_CreateArray();

    for (std::vector<Point>::iterator iter = pLine->points.begin(); iter != pLine->points.end(); ++iter)
    {
        cJSON *pointNode = cJSON_CreateObject();
        cJSON_AddNumberToObject(pointNode, "id", iter->id);
        cJSON_AddNumberToObject(pointNode, "x", iter->x);
        cJSON_AddNumberToObject(pointNode, "y", iter->y);
        cJSON_AddNumberToObject(pointNode, "t", iter->t);
        if (iter->avoidDis >= 0)
        {
            cJSON_AddNumberToObject(pointNode, "avoid_dis", iter->avoidDis);
        }
        cJSON_AddItemToArray(pointsNode, pointNode);
    }
    cJSON_AddItemToObject(node, "points", pointsNode);
    cJSON   *limitNode = cJSON_CreateObject();
    cJSON_AddNumberToObject(limitNode, "x", pLine->limit.x);
    cJSON_AddNumberToObject(limitNode, "w", pLine->limit.w);
    cJSON_AddItemToObject(node, "limit", limitNode);
    return 0;
}

int _JsonDecodeLine(cJSON *node, Line *pLine, std::string& failMsg)
{
    int iRet = 0, eleNum;
    cJSON *item, *subItem, *subItem2;
    do
    {
        item = cJSON_GetObjectItem(node, "type");
        if ((item == NULL) || (item->type != cJSON_String))
        {
            iRet = -1;
            failMsg += "bad type";
            break;
        }
        pLine->type = item->valuestring;
        item = cJSON_GetObjectItem(node, "points");
        if ((item == NULL) || (item->type != cJSON_Array))
        {
            iRet = -2;
            failMsg += "bad points";
            break;
        }
        eleNum = cJSON_GetArraySize(item);
        if (eleNum < 2)
        {
            iRet = -2;
            failMsg += "bad point count";
            break;
        }
        char buf[64];
        for (int i = 0; i < eleNum; i++)
        {
            subItem = cJSON_GetArrayItem(item, i);
            Point pt;
            subItem2 = cJSON_GetObjectItem(subItem, "x");
            if ((subItem2 == NULL) || (subItem2->type != cJSON_Number))
            {
                iRet = -10 * (i + 1) - 1;
                sprintf(buf, "bad pt[%d]. x ", i);
                break;
            }
            pt.x = subItem2->valuedouble;
            subItem2 = cJSON_GetObjectItem(subItem, "y");
            if ((subItem2 == NULL) || (subItem2->type != cJSON_Number))
            {
                iRet = -10 * (i + 1) - 2;
                sprintf(buf, "bad pt[%d].y ", i);
                break;
            }
            pt.y = subItem2->valuedouble;
            subItem2 = cJSON_GetObjectItem(subItem, "t");
            if ((subItem2 == NULL) || (subItem2->type != cJSON_Number))
            {
                iRet = -10 * (i + 1) - 3;
                sprintf(buf, "bad pt[%d].t ", i);
                break;
            }
            pt.t = subItem2->valuedouble;
            subItem2 = cJSON_GetObjectItem(subItem, "id");
            if ((subItem2 == NULL) || (subItem2->type != cJSON_Number))
            {
                iRet = -10 * (i + 1) - 4;
                sprintf(buf, "bad pt[%d].id ", i);
                break;
            }
            pt.id = subItem2->valueint;
            if (pt.id <= 0)
            {
                iRet = -10 * (i + 1) - 4;
                sprintf(buf, "bad pt[%d].id ", i);
                break;
            }
            pLine->points.push_back(pt);
        }
        if (iRet != 0)
        {
            failMsg = std::string(buf);
            break;
        }
        item = cJSON_GetObjectItem(node, "limit");
        if ((item == NULL) || (item->type != cJSON_Object))
        {
            iRet = -3;
            failMsg += "bad limit";
            break;
        }
        subItem = cJSON_GetObjectItem(item, "x");
        if ((subItem == NULL) || (subItem->type != cJSON_Number))
        {
            iRet = -5;
            failMsg += "bad limit.x";
            break;
        }
        pLine->limit.x = subItem->valuedouble;
        subItem = cJSON_GetObjectItem(item, "w");
        if ((subItem == NULL) || (subItem->type != cJSON_Number))
        {
            iRet = -6;
            failMsg += "bad limit.w";
            break;
        }
        pLine->limit.w = subItem->valuedouble;
    }
    while (false);
    return iRet;
}

int ubtNavEncodeStartReq(std::string&  buf, ubt_nav_start_req *pStartReq, std::string& failDesc)
{
    cJSON *rootNode = cJSON_CreateObject();
    cJSON_AddStringToObject(rootNode, "task_id", pStartReq->taskId.c_str());
    cJSON *pathNode = cJSON_CreateArray();
    for (std::vector<Line>::iterator iter = pStartReq->path.begin(); iter != pStartReq->path.end(); ++iter)
    {
        cJSON *lineNode = cJSON_CreateObject();
        _JsonEncodeLine(lineNode, &*iter, failDesc);
        cJSON_AddItemToArray(pathNode, lineNode);
    }
    cJSON_AddItemToObject(rootNode, "path", pathNode);

    cJSON *paramsNode = cJSON_CreateObject();
    cJSON_AddNumberToObject(paramsNode, "ttl", pStartReq->params.ttl);
    cJSON_AddNumberToObject(paramsNode, "wait_line_index", pStartReq->params.waitLineIndex);
    cJSON_AddNumberToObject(paramsNode, "wait_point_id", pStartReq->params.waitPointId);
    cJSON_AddItemToObject(rootNode, "params", paramsNode);

    char *str = cJSON_PrintBuffered(rootNode, 4096, 0);
    buf = str;
    free(str);
    return 0;
}

int ubtNavEncodeStopReq(std::string&  buf, ubt_nav_stop_req *pStopReq, std::string& failDesc)
{
    char bufTmp[64];
    sprintf(bufTmp, "duration=%d&clean=%d&stop_reason=%d", pStopReq->duration, pStopReq->clean, pStopReq->reason);
    buf += std::string(bufTmp);
    return 0;
}

int ubtNavEncodeStatus(std::string&	buf, ubt_nav_status *pStatus, std::string& failDesc)
{
    char bufTmp[1024];
    bufTmp[sizeof(bufTmp) - 1] = 0;
    snprintf(bufTmp, sizeof(bufTmp) - 1,
             "state=%d&flag=%d&stop_state=%d&stop_reason=%d&ttl=%d&line_index=%d&isRotate=%d&last_point_id=%d&next_point_id=%d&obstacle=%d&spdx=%f&wait_line_index=%d&wait_point_id=%d&task_id=%s&stop_reason_desc=%s",
             pStatus->state, pStatus->flag, pStatus->stopState, pStatus->stopReason, pStatus->ttl, pStatus->lineIndex, pStatus->isRotate,
             pStatus->lastPointId, pStatus->nextPointId, pStatus->obstacle, pStatus->spdx,
             pStatus->waitLineIndex, pStatus->waitPointId, pStatus->taskId.c_str(), pStatus->stopReasonDesc.c_str());
    return 0;
}

int ubtNavEncodeSetoptReq(std::string&	buf, ubt_nav_setopt_req *pSetoptReq, std::string& failDesc)
{
    char bufTmp[64];
    sprintf(bufTmp, "ttl=%d&wait_line_index=%d&wait_point_id=%d", pSetoptReq->ttl, pSetoptReq->waitLineIndex, pSetoptReq->waitPointId);
    buf += std::string(bufTmp);
    return 0;
}

int ubtNavDecodeComRsp(std::string& buf, ubt_nav_msg_com_rsp *pComRsp, std::string& failDesc)
{
    std::map<std::string, std::string> paramMap = ubt_com::ParseUrlQuery(buf);
    pComRsp->result = 0;
    pComRsp->desc = "";
    for (std::map<std::string, std::string>::iterator iter = paramMap.begin(); iter != paramMap.end(); ++iter)
    {
        if (iter->first == "result")
        {
            pComRsp->result = atoi(iter->second.c_str());
        }
        else if (iter->first == "desc")
        {
            pComRsp->desc = iter->second;
        }
        else
        {
            ;
        }
    }
    return 0;
}

int ubtNavDecodeStartReq(std::string& buf, ubt_nav_start_req *pStartReq, std::string& failMsg)
{
    int iRet = 0, iRes, eleNum;
    cJSON *item, *subItem, *subItem2;
    try
    {
        do
        {
            cJSON *root = cJSON_Parse(buf.c_str());
            if (root == NULL)
            {
                iRet = -1;
                break;
            }
            item = cJSON_GetObjectItem(root, "task_id");
            if ((item == NULL) || (item->type != cJSON_String))
            {
                iRet = -1;
                failMsg += "bad type";
                break;
            }
            pStartReq->taskId = item->valuestring;

            item = cJSON_GetObjectItem(root, "path");

            if ((item == NULL) || (item->type != cJSON_Array))
            {
                iRet = -2;
                failMsg += "bad path";
                break;
            }
            eleNum = cJSON_GetArraySize(item);
            char buf[64];
            std::string failReason;
            for (int i = 0; i < eleNum; i++)
            {
                subItem = cJSON_GetArrayItem(item, i);
                Line line;
                iRes = _JsonDecodeLine(subItem, &line, failMsg);
                if (iRes != 0)
                {
                    sprintf(buf, "line %d ", i);
                    iRet = -100 * (i + 1) + iRes;
                    failMsg += std::string(buf);
                    failMsg += failReason;
                    break;
                }
                pStartReq->path.push_back(line);
            }
            if (iRet != 0)
            {
                break;
            }
        }
        while (false);
    }
    catch (...)
    {
        iRet = -100;
    }
    return iRet;
}

int ubtNavDecodeStopReq(std::string&  buf, ubt_nav_stop_req *pStopReq, std::string& failDesc)
{
    std::map<std::string, std::string> paramMap = ubt_com::ParseUrlQuery(buf);
    pStopReq->reason = 0;
    pStopReq->duration = 0;
    pStopReq->clean = 0;
    for (std::map<std::string, std::string>::iterator iter = paramMap.begin(); iter != paramMap.end(); ++iter)
    {
        if (iter->first == "reason")
        {
            pStopReq->reason  = atoi(iter->second.c_str());
        }
        else if (iter->first == "duration")
        {
            pStopReq->duration  = atoi(iter->second.c_str());
        }
        else if (iter->first == "clean")
        {
            pStopReq->clean  = atoi(iter->second.c_str());
        }
        else
        {
            ;
        }
    }
    return 0;
}

int ubtNavDecodeStatus(std::string& buf, ubt_nav_status *pStatus, std::string& failDesc)
{
    std::map<std::string, std::string> paramMap = ubt_com::ParseUrlQuery(buf);
    pStatus->state = 0;
    //pStatus->taskId
    pStatus->flag = 0;
    pStatus->stopState = 0;
    pStatus->stopReason = 0;
    pStatus->ttl = 0;
    pStatus->lineIndex = 0;
    pStatus->isRotate = 0;
    pStatus->lastPointId = 0;
    pStatus->nextPointId = 0;
    pStatus->obstacle = 0;
    pStatus->spdx = 0.0;
    pStatus->waitLineIndex = -2;
    pStatus->waitPointId = -2;

    for (std::map<std::string, std::string>::iterator iter = paramMap.begin(); iter != paramMap.end(); ++iter)
    {
        if (iter->first == "state")
        {
            pStatus->state  = atoi(iter->second.c_str());
        }
        else if (iter->first == "task_id")
        {
            pStatus->taskId   = iter->second;
        }
        else if (iter->first == "flag ")
        {
            pStatus->flag   = atoi(iter->second.c_str());
        }
        else if (iter->first == "stop_state")
        {
            pStatus->stopState = atoi(iter->second.c_str());
        }
        else if (iter->first == "stop_reason")
        {
            pStatus->stopReason  = atoi(iter->second.c_str());
        }
        else if (iter->first == "ttl")
        {
            pStatus->ttl  = atoi(iter->second.c_str());
        }
        else if (iter->first == "line_Index")
        {
            pStatus->lineIndex  = atoi(iter->second.c_str());
        }
        else if (iter->first == "isRotate")
        {
            pStatus->isRotate  = atoi(iter->second.c_str());
        }
        else if (iter->first == "last_point_id")
        {
            pStatus->lastPointId  = atoi(iter->second.c_str());
        }
        else if (iter->first == "next_point_id")
        {
            pStatus->nextPointId  = atoi(iter->second.c_str());
        }
        else if (iter->first == "obstacle")
        {
            pStatus->obstacle  = atoi(iter->second.c_str());
        }
        else if (iter->first == "spdx")
        {
            pStatus->spdx  = atof(iter->second.c_str());
        }
        else if (iter->first == "wait_line_index")
        {
            pStatus->waitLineIndex  = atoi(iter->second.c_str());
        }
        else if (iter->first == "wait_point_id")
        {
            pStatus->waitPointId  = atoi(iter->second.c_str());
        }
        else if (iter->first == "stop_reason_desc")
        {
            pStatus->stopReasonDesc  = iter->second;
        }
        else
        {
            ;
        }
    }
    return 0;
}

int ubtNavDecodeSetoptReq(std::string& buf, ubt_nav_setopt_req *pSetoptReq, std::string& failDesc)
{
    std::map<std::string, std::string> paramMap = ubt_com::ParseUrlQuery(buf);
    pSetoptReq->ttl = -1;
    pSetoptReq->waitLineIndex = -1;
    pSetoptReq->waitPointId = -1;
    for (std::map<std::string, std::string>::iterator iter = paramMap.begin(); iter != paramMap.end(); ++iter)
    {
        if (iter->first == "ttl")
        {
            pSetoptReq->ttl  = atoi(iter->second.c_str());
        }
        else if (iter->first == "wait_line_index")
        {
            pSetoptReq->waitLineIndex  = atoi(iter->second.c_str());
        }
        else if (iter->first == "wait_point_id")
        {
            pSetoptReq->waitPointId  = atoi(iter->second.c_str());
        }
        else
        {
            ;
        }
    }
    return 0;

}

}


